/*
 * riodp_db.c
 *
 *  Created on: 2021年3月15日
 *      Author: root
 */

#include "riodp_db.h"
#include "rapidio_mport_mgmt.h"
#include "riocpplib.h"

static volatile sig_atomic_t rcv_exit;
static volatile sig_atomic_t report_status;
static int exit_no_dev;


int bslRioSendDoorbell(uint32_t rioid, uint16_t dbval)
{
	struct riomp_mgmt_event evt;
	int ret = 0;

	evt.header = RIO_EVENT_DOORBELL;
	evt.u.doorbell.rioid = rioid;
	evt.u.doorbell.payload = dbval;

	/** - send a single doorbell message to a target device */
	ret = riomp_mgmt_send_event(mport_hnd, &evt);
	if (ret < 0)
	{
		printf("Write DB event failed, err=%d\n", ret);
	}
	return ret;
}


static void db_sig_handler(int signum)
{
	switch(signum) {
	case SIGTERM:
		rcv_exit = 1;
		break;
	case SIGINT:
		rcv_exit = 1;
		break;
	case SIGUSR1:
		report_status = 1;
		break;
	}
}

static void test_sigaction(int UNUSED(sig), siginfo_t *siginfo, void *UNUSED(context))
{
	printf ("SIGIO info PID: %ld, UID: %ld CODE: 0x%x BAND: 0x%lx FD: %d\n",
			(long)siginfo->si_pid, (long)siginfo->si_uid, siginfo->si_code,
			siginfo->si_band, siginfo->si_fd);
	exit_no_dev = 1;
}

int bslRioRecvDoorbell(uint32_t rioid)
{
	int ret;
	struct riomp_mgmt_event evt;
	struct sigaction action;
	uint16_t start=0;
	uint16_t end=0xffff;

	memset(&action, 0, sizeof(action));
	action.sa_sigaction = test_sigaction;
	action.sa_flags = SA_SIGINFO;
	sigaction(SIGIO, &action, NULL);

	/* Trap signals that we expect to receive */
	signal(SIGINT,  db_sig_handler);
	signal(SIGTERM, db_sig_handler);
	signal(SIGUSR1, db_sig_handler);

	riomp_mgmt_set_event_mask(mport_hnd, RIO_EVENT_DOORBELL);

	/** - enable receiving doorbells in specified range */
	ret = riomp_mgmt_dbrange_enable(mport_hnd, rioid, start, end);
	if (ret)
	{
		printf("Failed to enable DB range, err=%d\n", ret);
		return ret;
	}


	/** - until terminated receive and display doorbell information */
	while (!rcv_exit)
	{
		if (exit_no_dev)
		{
			printf(">>> Device removal signaled <<<\n");
			break;
		}
		ret = riomp_mgmt_get_event(mport_hnd, &evt);
		if (ret < 0)
		{
			if (ret == -EAGAIN)
			{
				continue;
			}
			else
			{
				printf("Failed to read event, err=%d\n", ret);
				break;
			}
		}
		if (evt.header == RIO_EVENT_DOORBELL)
		{
			printf("DB 0x%04x from destID %d\n",evt.u.doorbell.payload, evt.u.doorbell.rioid);
			sem_post(&srioSemInput);
		}
		else
		{
			printf("Ignoring event type %d)\n", evt.header);
		}
	}
	/** - on exit, disable specified doorbell range */
	ret = riomp_mgmt_dbrange_disable(mport_hnd, rioid, start, end);
	if (ret)
	{
		printf("Failed to disable DB range, err=%d\n", ret);
		return ret;
	}
	return 0;
}


